//
// Created by LiuYou on 2021/5/8.
//

#include <cstring>
#include "CMyString.hpp"

CMyString::CMyString(char* mPData) {
    if (mPData == nullptr) {
        m_PData = new char[1]();
        m_PData[0] = '\0';
    } else {
        m_PData = new char[std::strlen(mPData) + 1]();
        std::memset(m_PData, '\0', std::strlen(mPData) + 1);
        std::strcpy(m_PData, mPData);
    }
}

CMyString::CMyString(const CMyString& str) {
    m_PData = new char[std::strlen(str.getMPData()) + 1]();
    std::memset(m_PData, '\0', std::strlen(str.getMPData()) + 1);
    std::strcpy(m_PData, str.getMPData());
}

CMyString::~CMyString() {
    delete[] m_PData;
}

/**
 * @brief 可以运行成功, 但是不是异常安全。
 * @param rhs
 * @return
 */
//CMyString&
//CMyString::operator=(const CMyString& rhs) {
//    if (this == &rhs) {
//        return *this;
//    } else {
//        delete[] m_PData;
//        // TODO 注意: 这里可能内存不足导致new char抛出异常, m_PData将是一个空指针, 这样非常容易导致程序崩溃。
//        //  改进如下
//        m_PData = new char[std::strlen(rhs.m_PData) + 1]();
//        std::memset(m_PData, '\0', std::strlen(rhs.m_PData) + 1);
//        std::strcpy(m_PData, rhs.m_PData);
//        return *this;
//    }
//}

/**
 * @brief 可以运行成功, 而且异常安全。
 * @param rhs
 * @return
 */
//CMyString&
//CMyString::operator=(const CMyString& rhs) {
//    if (this == &rhs) {
//        return *this;
//    } else {
//        // 这种办法是我们先用new分配新的内存空间, 再用delete释放已有的内容。
//        // 这样只在分配内容成功之后再释放原来的内容, 也就是当分配内存失败时我们能确保CMyString的原来的实例不会被修改。
//        // 还有一个改进的方法如下
//        char* ptrTemp = new char[std::strlen(rhs.m_PData) + 1]();
//        delete[] m_PData;
//        m_PData = ptrTemp;
//        std::memset(m_PData, '\0', std::strlen(rhs.m_PData) + 1);
//        std::strcpy(m_PData, rhs.m_PData);
//        return *this;
//    }
//}

/**
 * @brief 可以运行成功, 而且异常安全。
 * @param rhs
 * @return
 */
CMyString&
CMyString::operator=(const CMyString& rhs) {
    if (this == &rhs) {
        return *this;
    } else {
        // 我们在CMyString的拷贝构造函数中使用new分配内存。如果
        // 由于内存不足抛出诸如bad_alloc等异常, 但是我们还没有修改原来实例的状态, 因此实例的状态还是有效的, 这也就保证了
        // 异常安全性。
        CMyString temp(rhs);
        char* ptrTemp = temp.m_PData;
        temp.m_PData = m_PData;
        m_PData = ptrTemp;
        return *this;
    }
}

char* CMyString::getMPData() const {
    return m_PData;
}
